package io.xxx.xbutler.core.get;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.xxx.xbutler.client.StoreClient;
import io.xxx.xbutler.client.TradeClient;
import io.xxx.xbutler.common.RedisKeys;
import io.xxx.xbutler.data.VirtualUserMapper;
import io.xxx.xbutler.domain.Order;
import io.xxx.xbutler.domain.StoreOrder;
import io.xxx.xbutler.domain.Venue;
import io.xxx.xbutler.domain.VirtualUser;
import io.xxx.xbutler.domain.task.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.CheckReturnValue;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 门店截单提醒
 */
@Slf4j
@Component
public class StorePurchaseReminderGetter implements ContentGetter {

    @Resource
    private StoreClient storeClient;

    @Resource
    private TradeClient tradeClient;

    @Resource
    private VirtualUserMapper virtualUserMapper;

    @Resource
    private RedissonClient redissonClient;

    @Value("${store.prime-day.order-share.suffix:已购物}")
    private String storePrimeDaySuffix;


    @Override
    public void replaceContent(PushContext context) {
        LocalDateTime now = LocalDateTime.now();

        Task task = context.getTask();
        Receiver receiver = context.getReceiver();
        Long storeId = receiver.getStoreId();
        if (task.getScene() != TaskScene.OrderShareReply || storeId == null) {
            return;
        }

        List<TaskItem> taskItems = context.getTaskItems();
        Map<MessageType, TaskItem> itemMap = taskItems.stream()
                .collect(Collectors.toMap(TaskItem::getMessageType, it -> it));
        TaskItem textItem = itemMap.get(MessageType.TEXT);
        TaskItem miniProgramItem = itemMap.get(MessageType.MINI_PROGRAM);

        LocalDate date = now.toLocalDate();
        boolean isPrimeDay = isPrimeDay(storeId, date);
        if (isPrimeDay) {
            StoreOrder storeOrder = storeClient.getStoreOrder(storeId, date);
            String text = storeOrder.getActivityCopywriter()
                    .replaceAll("<div>", "")
                    .replaceAll("</div>", "\n");
            JSONObject textContent = new JSONObject() {{
                put("text", text);
            }};
            textItem.setContent(textContent);

            Venue venue = storeOrder.getVenue();
            JSONObject miniProgramContent = ContentGetter.buildMiniProgram(venue.getDescription(), venue.getThumbUrl(), venue.getPagePath());
            miniProgramItem.setContent(miniProgramContent);
        } else {
            List<Order> storeOrders = tradeClient.getStoreOrders(storeId, date);
            log.info("门店订单列表[taskId:{}, taskItemId:{}, storeId:{}, storeCode:{}, orders:{}]",
                    task.getId(), textItem.getId(), storeId, receiver.getStoreCode(), JSON.toJSONString(storeOrders));
            List<String> orderUserNames = storeOrders.stream()
                    .map(Order::getWechatName)
                    .distinct()
                    .toList();

            RMap<String, Boolean> cachedOrderUsers = redissonClient.getMap(RedisKeys.storePrimeDayOrderUsers(storeId, date));
            String text = appendUsers(task, textItem, receiver, cachedOrderUsers, orderUserNames);
            JSONObject textContent = new JSONObject() {{
                put("text", text);
            }};
            textItem.setContent(textContent);
        }
    }

    private boolean isPrimeDay(Long storeId, LocalDate date) {
        LocalDate primeDay = storeClient.getPrimeDay(storeId);
        return primeDay.equals(date);
    }

    private String appendUsers(Task task,
                               TaskItem item,
                               Receiver receiver,
                               RMap<String, Boolean> cachedOrderUsers,
                               List<String> orderUserNames) {
        if (cachedOrderUsers.isEmpty()) { // 每天第一次发送
            if (ObjectUtils.isEmpty(orderUserNames)) {
                VirtualUser randomVirtualUser = getRandomVirtualUser(null);
                if (randomVirtualUser == null) {
                    log.info("门店没有用户下单且未配置虚拟用户[taskId:{}, taskItemId:{}, storeId:{}, storeCode:{}, receiverType:{}, receiverId:{}]",
                            task.getId(), item.getId(), receiver.getStoreId(), receiver.getStoreCode(), receiver.getType(), receiver.getId());
                    return null;
                } else {
                    cachedOrderUsers.put(randomVirtualUser.getName(), false);
                }
            } else {
                for (String userName : orderUserNames) {
                    cachedOrderUsers.put(userName, true);
                }
            }
        } else {    // 不是第一次发送
            Map<Boolean, List<Map.Entry<String, Boolean>>> cachedOrderUsersMap = cachedOrderUsers.entrySet()
                    .stream()
                    .collect(Collectors.partitioningBy(Map.Entry::getValue));
            List<String> actualUsers = cachedOrderUsersMap.get(true)
                    .stream()
                    .map(Map.Entry::getKey)
                    .toList();
            List<String> virtualUsers = cachedOrderUsersMap.get(false)
                    .stream()
                    .map(Map.Entry::getKey)
                    .toList();

            if (actualUsers.size() >= orderUserNames.size()) { // 真实的下单用户并未增加，需抽取一个虚拟用户
                VirtualUser randomVirtualUser = getRandomVirtualUser(virtualUsers);
                if (randomVirtualUser != null) {
                    cachedOrderUsers.put(randomVirtualUser.getName(), false);
                } else {
                    log.warn("虚拟用户已经取完了[taskId:{}, taskItemId:{}, storeId:{}, storeCode:{}]",
                            task.getId(), item.getId(), receiver.getStoreId(), receiver.getStoreCode());
                }
            } else {
                List<String> subUsers = orderUserNames.subList(actualUsers.size(), orderUserNames.size());
                for (String user : subUsers) {
                    cachedOrderUsers.put(user, true);
                }
            }
        }

        JSONObject content = item.getContent();
        StringBuilder builder = new StringBuilder(content.getString("text"));
        List<String> cachedOrderUserNames = new ArrayList<>(cachedOrderUsers.keySet());
        if (cachedOrderUserNames.size() <= 10) {
            /*
            1、xxx 已下单
            2、yyy 已下单
             */
            for (int i = 0; i < cachedOrderUserNames.size(); i++) {
                builder.append("\n").append(i + 1).append("、").append(cachedOrderUserNames.get(i)).append(" ").append(storePrimeDaySuffix);
            }
        } else {
            /*
            1、xxx 等5人已下单
            6、yyy 已下单
             */
            builder.append("\n1、")
                    .append(cachedOrderUserNames.getFirst()).append(" 等")
                    .append(cachedOrderUserNames.size() - 9).append("人")
                    .append(storePrimeDaySuffix);
            for (int i = cachedOrderUserNames.size() - 9; i < cachedOrderUserNames.size(); i++) {
                builder.append("\n").append(i + 1).append("、").append(cachedOrderUserNames.get(i)).append(" ").append(storePrimeDaySuffix);
            }
        }
        return builder.toString();
    }

    @CheckReturnValue
    private VirtualUser getRandomVirtualUser(List<String> userNames) {
        LambdaQueryWrapper<VirtualUser> wrapper = new LambdaQueryWrapper<>();
        if (!ObjectUtils.isEmpty(userNames)) {
            wrapper.notIn(VirtualUser::getName, userNames);
        }
        wrapper.last("order by rand() limit 1");
        return virtualUserMapper.selectOne(wrapper);
    }
}
